<!--
 * @Author: your name
 * @Date: 2021-03-15 20:53:56
 * @LastEditTime: 2021-03-15 20:56:17
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edi
 * @FilePath: \study\js\面试题\数组计算.html
-->
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>

    <body>
        <p><a href="https://blog.csdn.net/weixin_42412046/article/details/81459294">js数组去重的10种方法</a></p>
        <p>callapply</p>
        <p>微妙的差距！ 从上面四个结果不难看出: call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象，第二个参数差别就来了： call 的参数是直接放进去的，第二第三第 n</p>
        <p>个参数全都用逗号分隔，直接放到后面 obj.myFun.call(db,'成都', ... ,'string' )。 apply 的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['成都', ..., 'string' ])。 bind</p>
        <p>除了返回是函数以外，它 的参数和 call 一样。 当然，三者的参数不限定是 string 类型，允许是各种类型，包括函数 、 object 等等！</p>
        <script>
            function test(a, b, c) {
                console.log('test - ', this, a, b, c);
            }

            test.call({ a: 1 }, 1, 2, 3);
            test.apply({ a: 2 }, [1, 2, 3]);

            function demo1() {
                test.apply({ a: 3 }, arguments);
            }
            function demo2(...args) {
                test.apply({ a: 4 }, args);
            }
            function demo3(...args) {
                console.log(Array.prototype.slice.call(arguments, 1));
                console.log(Array.prototype.slice.call(arguments, 1));
                // console.log(Array.prototype.splice.call(arguments, 1, 0, 55));
                test.apply({ a: 5 }, Array.prototype.slice.call(arguments, 1));
            }

            demo1(5, 6, 7);
            demo2(8, 9, 10);
            demo3(18, 19, 110);

            let a = 1;
            let o = { name: 'obj' };

            function f1(params) {
                console.log(this, params, arguments);

                console.log([...arguments].slice(1));
            }
            f1(1);
            // bind 返回函数
            f1.bind(o)(666, 777);
            f2 = f1.bind(o);
            f2(999, 888);

            // f1.call(window, 2);
            // f1.call(o, 3);
            // f1.call(o, 3, 'a', 'b');

            // f1.apply(o, [1, 'n', 9]);

            var max = Math.max.apply(null, [1, 4, 67, 8]);
            console.log('max ', max);
            var min = Math.min.apply(null, [-31, 4, 67, 8]);
            console.log('min ', min);

            var arr1 = new Array('1', '2', '3');
            var arr2 = new Array('4', '5', '6');
            //得到合并后数组的长度，因为push就是返回一个数组的长度
            Array.prototype.push.apply(arr1, arr2);

            Function.prototype.myCall = function () {
                if (typeof this !== 'function') {
                    throw new TypeError('not funciton');
                }
                let [context, ...args] = [...arguments];
                context = context || window;
                context.fn = this;
                let res = context.fn(...args);
                delete context.fn;
                return res;
            };

            let a1 = Array.prototype.shift.myCall([6, 7, 8]);
            let a2 = Array.prototype.slice.myCall([6, 7, 8], 1);
            console.log(a1);
            console.log(arr2);

            Function.prototype.myApply = function (context) {
                if (typeof this !== 'function') {
                    throw new TypeError('not funciton');
                }
                context = context || window;
                context.fn = this;
                let result;
                if (arguments[1]) {
                    result = context.fn(...arguments[1]);
                } else {
                    result = context.fn();
                }
                delete context.fn;
                return result;
            };

            // 思路：类似call，但返回的是函数
            Function.prototype.mybind = function (context) {
                if (typeof this !== 'function') {
                    throw new TypeError('Error');
                }
                let _this = this;
                let arg = [...arguments].slice(1);
                return function F() {
                    // 处理函数使用new的情况
                    if (this instanceof F) {
                        return new _this(...arg, ...arguments);
                    } else {
                        return _this.apply(context, arg.concat(...arguments));
                    }
                };
            };
        </script>
    </body>
</html>
